/*
 * Copyright (c) GoKeep by gokeep.org. 2022-2023. All rights reserved
 */
package org.gokeep.common.component;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.gokeep.common.config.GlobalConfig;
import org.gokeep.common.config.properties.AuthProperties;
import org.gokeep.common.constant.enums.ClientTypeEnum;
import org.gokeep.common.dto.RsaKeyPair;
import org.gokeep.common.dto.TokenPayload;
import org.gokeep.common.util.DateUtil;
import org.gokeep.common.util.JsonUtil;
import org.springframework.stereotype.Component;

import java.util.Map;

import static org.gokeep.common.config.GlobalConfig.TOKEN_EXPIRE_TIME_OF_DAY;

/**
 * @author xuning
 */
@Slf4j
@Component
public class TokenComponent {

    private RsaKeyPair rsaKeyPair;

    private Algorithm algorithm;

    private JWTVerifier jwtVerifier;

    private static final String JWT_TOKEN_SUBJECT = "gokeep.org sign token";

    /**
     * double-check
     * 获取rsa操作对象
     *
     * @return
     */
    private RsaKeyPair getRsaKeyPair() {
        if (this.rsaKeyPair == null) {
            this.rsaKeyPair = new RsaKeyPair().getConfigRsaKeyPair();
            return this.rsaKeyPair;
        }
        return this.rsaKeyPair;
    }

    /**
     * 获取加密算法
     *
     * @return
     */
    private Algorithm getAlgorithm() {
        if (this.algorithm == null) {
            this.algorithm = Algorithm.RSA256(getRsaKeyPair().getPublicKey(), getRsaKeyPair().getPrivateKey());
            return this.algorithm;
        } else {
            return this.algorithm;
        }
    }

    /**
     * 校验token并获取decode属性
     *
     * @param token
     * @return
     */
    private DecodedJWT verifyTokenWithDecode(String token) {
        return getJWTVerifier().verify(token);
    }


    /**
     * 获取JwtToken校验器
     *
     * @return
     */
    private JWTVerifier getJWTVerifier() {
        if (this.jwtVerifier == null) {
            Algorithm tokenAlgorithm = getAlgorithm();
            this.jwtVerifier = JWT.require(tokenAlgorithm).build();
            return this.jwtVerifier;
        }
        return this.jwtVerifier;
    }


    /**
     * 生成Token
     *
     * @return
     */
    public String generateToken(TokenPayload payload) {
        Algorithm tokenAlgorithm = getAlgorithm();
        JWTCreator.Builder builder = JWT.create()
                .withIssuer(GlobalConfig.DEFAULT_ISSUER_NAME)
                .withAudience(payload.getUserId())
                .withSubject(JWT_TOKEN_SUBJECT)
                .withExpiresAt(DateUtil.getAfterDay(TOKEN_EXPIRE_TIME_OF_DAY));
        builder.withPayload(JsonUtil.toJson(payload));
        return builder.sign(tokenAlgorithm);
    }

    /**
     * 根据Token获取Payload
     *
     * @param token
     * @return
     */
    public TokenPayload verifyTokenGetPayload(String token) {
        DecodedJWT decodedJwt = verifyTokenWithDecode(token);
        Map<String, Claim> payload = decodedJwt.getClaims();
        return new TokenPayload()
                .setUserId(payload.get("userId").asString())
                .setUsername(payload.get("username").asString())
                .setAtExpireTime(payload.get("exp").asLong() * 1000L)
                .setClientType(payload.get("clientType").as(ClientTypeEnum.class));
    }


    /**
     * 校验token
     * @param token
     * @return
     */
    public boolean verify(String token) {
        try {
            verifyTokenWithDecode(token);
        }catch (Exception e) {
            return false;
        }
        return true;
    }
}